package com.gaofans.nrpc.client.route;

import com.gaofans.nrpc.common.processor.CommonEventProcessor;
import com.gaofans.nrpc.common.processor.EventListener;
import com.gaofans.nrpc.common.processor.ServiceAuthority;

import java.net.URI;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 路由器
 * @author GaoFans
 */
public abstract class Router implements Comparable<Router> {

    private final int order;
    private final String name;
    private final RouterPredicate predicate;
    private final CommonEventProcessor<ServiceEvent<ServiceAuthority>,String> processor;

    public Router(int order, String name, RouterPredicate predicate) {
        this.order = order;
        this.name = name;
        this.predicate = predicate;
        this.processor = new CommonEventProcessor<>();
    }

    /**
     * 启动路由器
     * @param
     */
    public void start(){};

    /**
     * 根据uri获取host:ip
     * @param uri
     * @return
     */
    public abstract ServiceAuthority find(URI uri);

    public void addListener(String listenerName, EventListener<ServiceEvent<ServiceAuthority>> listener){
        processor.register(listenerName,listener);
    }

    /**
     * 关闭路由器
     */
    public void stop(){};

    public int getOrder() {
        return order;
    }

    public String getName() {
        return name;
    }

    public RouterPredicate getPredicate() {
        return predicate;
    }

    /**
     * 获取order的优先级
     * @return
     */
    public int order(){
        return this.order;
    }

    /**
     * 判断uri是否与当前路由匹配
     * @param uri
     * @return
     */
    public boolean match(URI uri){
        return predicate.test(uri);
    }

    /**
     * 比较router之间的优先级
     * @param router
     * @return
     */
    @Override
    public int compareTo(Router router){
        return order()>= router.order()?1:-1;
    };

    protected void publish(String name, ServiceAuthority authority, ServiceEvent.EventType type){
        processor.get(name).onDataChunk(new ServiceEvent<>(type,authority));
    }

    protected void publishAll(ServiceAuthority authority, ServiceEvent.EventType type){
        Set<Map.Entry<String, EventListener<ServiceEvent<ServiceAuthority>>>> entries = processor.all().entrySet();
        for (Map.Entry<String, EventListener<ServiceEvent<ServiceAuthority>>> entry : entries) {
            entry.getValue().onDataChunk(new ServiceEvent<>(type,authority));
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Router)) return false;
        Router router = (Router) o;
        return getOrder() == router.getOrder() && getName().equals(router.getName());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getOrder(), getName());
    }
}
